package item35;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 第35条：注解优先于命名模式
 */
public class Main {

    public static void main(String[] args) throws Exception {

        int tests = 0;
        int passed = 0;
        Class testClass = Main.class;
        for (Method m : testClass.getDeclaredMethods()) {
            if (m.isAnnotationPresent(Test.class)) {
                tests++;
                try {
                    m.invoke(null);
                    passed++;
                } catch (InvocationTargetException wrappedExc) {
                    Throwable exc = wrappedExc.getCause();
                    System.out.println(m + " failed: " + exc);
                } catch (Exception exc) {
                    System.out.println("INVALID @test: " + m);
                }
            }
        }
        System.out.printf("Passed: %d, Failed: %d%n", passed, tests - passed);

        testClass = Sample2.class;
        for (Method m : testClass.getDeclaredMethods()) {
            if (m.isAnnotationPresent(ExceptionTest.class)) {
                tests++;
                try {
                    m.invoke(null);
                    System.out.printf("Test %s failed: no exception%n", m);
                } catch (InvocationTargetException wrappedExc) {
                    Throwable exc = wrappedExc.getCause();
                    Class<? extends Exception> excType = m.getAnnotation(ExceptionTest.class).value();
                    if (excType.isInstance(exc)) {
                        passed++;
                    } else {
                        System.out.printf("Test %s failed: expected %s, got %s%n", m , excType.getName(), exc);
                    }
                } catch (Exception exc) {
                    System.out.println("INVALID @test: " + m);
                }
            }
        }
        System.out.printf("Passed: %d, Failed: %d%n", passed, tests - passed);

        testClass = Sample3.class;
        for (Method m : testClass.getDeclaredMethods()) {
            if (m.isAnnotationPresent(ExceptionTest02.class)) {
                tests++;
                try {
                    m.invoke(null);
                    System.out.printf("Test %s failed: no exception%n", m);
                } catch (Throwable wrappedExc) {
                    Throwable exc = wrappedExc.getCause();
                    Class<? extends Exception>[] excTypes = m.getAnnotation(ExceptionTest02.class).value();
                    int oldPassed = passed;
                    for (Class<? extends Exception> excType : excTypes) {
                        if (excType.isInstance(exc)) {
                            passed++;
                            break;
                        }
                    }
                    if (passed == oldPassed)
                        System.out.printf("Test %s failed: %s %n", m, exc);
                }
            }
        }

        // 既然有了注解，就完全没有理由再使用命名模式了
        // 所有的程序员都应该使用java平台所提供的预定义的注解类型
    }

    @Test
    public static void m1() {} //Test should pass
    public static void m2() {}
    @Test
    public static void m3() {   // Test should fail
        throw new RuntimeException("Boom");
    }
    public static void m4() {}
    @Test
    public void m5() {} // INVALID USE: nonstatic method
    public static void m6() {}
    @Test
    public static void m7() { // Test should fail
        throw new RuntimeException("Crash");
    }
    public static void m8() {}

}
